﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;

namespace xBei.Redis.Extension {
    public partial class RedisClient {
        /// <summary>
        /// 写入数据流，<see href="https://redis.io/commands/set/"/>
        /// </summary>
        /// <param name="key"></param>
        /// <param name="stream"></param>
        /// <param name="seconds"></param>
        /// <returns></returns>
        public async Task<RedisClient> SetStreamAsync(string key, MemoryStream stream, int seconds = 315360000) {
            await (await GetDatabaseAsync()).StringSetAsync(GetKey(key), RedisValue.CreateFrom(stream), TimeSpan.FromSeconds(seconds), flags: CommandFlags.FireAndForget);
            return this;
        }
        /// <summary>
        /// 写入字节数组，<see href="https://redis.io/commands/set/"/>
        /// </summary>
        /// <param name="key"></param>
        /// <param name="buffer"></param>
        /// <param name="seconds"></param>
        /// <returns></returns>
        public async Task<RedisClient> SetBytesAsync(string key, byte[] buffer, int seconds = 315360000) {
            await (await GetDatabaseAsync()).StringSetAsync(GetKey(key), buffer, TimeSpan.FromSeconds(seconds), flags: CommandFlags.FireAndForget);
            return this;
        }
        /// <summary>
        /// 读取字节流，<see href="https://redis.io/commands/get/"/>
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<MemoryStream?> GetStreamAsync(string key) {
            var buffer = await GetBytesAsync(key);
            if (buffer == null) {
                return default;
            }
            return new MemoryStream(buffer);
        }
        /// <summary>
        /// 读取字节数组，<see href="https://redis.io/commands/get/"/>
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<byte[]?> GetBytesAsync(string key) {
            var db = await GetDatabaseAsync();
            var redisValue = await db.StringGetAsync(GetKey(key));
            return redisValue.HasValue ? (byte[]?)redisValue : default;
        }

        #region 队列 Queue 先进先出
        /// <summary>
        /// 把字节数组写入队列，<see href="https://redis.io/commands/rpush/"/>
        /// </summary>
        /// <param name="key"></param>
        /// <param name="bytes"></param>
        /// <param name="seconds">如果指定了超时时间，每次插入数据都会重置超时时间
        /// 同一个Key，如果第一次入队没有指定超时时间，之后的入队操作有指定超时时间，那么这个Key的超时时间就是按最后一次操作来。
        /// 同一个Key，如果在任何（除了最后）一次入队的时候指定了超时时间，但是最后一次没有指定，那么这个Key的超时时间是按“最后一次”有指定超时的入队操作来计算的。
        /// </param>
        /// <returns></returns>
        public async Task<RedisClient> EnqueueAsync(string key, byte[] bytes, int seconds = 315360000) {
            await (await GetDatabaseAsync()).ListRightPushAsync(GetKey(key), bytes, flags: CommandFlags.FireAndForget);
            return seconds > 0 ? await ExpireAsync(GetKey(key), seconds) : this;
        }
        /// <summary>
        /// 出队一个字节数组，<see href="https://redis.io/commands/lpop/"/>，没有队列，或者队列为空，返回 null
        /// </summary>
        /// <param name="Key"></param>
        /// <returns></returns>
        public async Task<byte[]?> DequeueBytesAsync(string Key) {
            var r = await (await GetDatabaseAsync()).ListLeftPopAsync(GetKey(Key));
            return r.IsNullOrEmpty ? default : r;
        }
        #endregion
        #region 队列 Stack 先进后出
        /// <summary>
        /// 入栈，<see href="https://redis.io/commands/lpush"/>
        /// </summary>
        /// <param name="key"></param>
        /// <param name="buffer"></param>
        /// <param name="seconds">如果指定了超时时间，每次插入数据都会重置超时时间
        /// 同一个Key，如果第一次入队没有指定超时时间，之后的入队操作有指定超时时间，那么这个Key的超时时间就是按最后一次操作来。
        /// 同一个Key，如果在任何（除了最后）一次入队的时候指定了超时时间，但是最后一次没有指定，那么这个Key的超时时间是按“最后一次”有指定超时的入队操作来计算的。
        /// </param>
        /// <returns></returns>
        public async Task<RedisClient> PushAsync(string key, byte[] buffer, int seconds = 315360000) {
            await (await GetDatabaseAsync()).ListLeftPushAsync(GetKey(key), buffer, flags: CommandFlags.FireAndForget);
            return seconds > 0 ? await ExpireAsync(GetKey(key), seconds) : this;
        }
        /// <summary>
        /// 出栈，<see href="https://redis.io/commands/rpop"/>，没有队列，或者队列为空，返回 null
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<byte[]?> PopBytesAsync(string key) {
            var r = await (await GetDatabaseAsync()).ListRightPopAsync(GetKey(key));
            return r.IsNullOrEmpty ? default : r;
        }
        #endregion
        #region Hash
        /// <summary>
        /// 设置Hash表（key）字段（field）的值，<see href="https://redis.io/commands/hset"/>
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <param name="buffer"></param>
        /// <param name="seconds">如果指定了超时时间，每次插入数据都会重置超时时间
        /// 同一个Key，如果第一次设置没有指定超时时间，之后的设置操作有指定超时时间，那么这个Key的超时时间就是按最后一次操作来。
        /// 同一个Key，如果在任何（除了最后）一次设置的时候指定了超时时间，但是最后一次没有指定，那么这个Key的超时时间是按“最后一次”有指定超时的设置操作来计算的。
        /// </param>
        /// <returns></returns>
        public async Task<RedisClient> HashSetAsync(string key, string field, byte[] buffer, int seconds = 315360000) {
            await (await GetDatabaseAsync()).HashSetAsync(GetKey(key), field, buffer, flags: CommandFlags.FireAndForget);
            if (seconds > 0) {
                await ExpireAsync(key, seconds);
            }
            return this;
        }
        /// <summary>
        /// 读取Hash表（key）字段（field）的值，<see href="https://redis.io/commands/hget"/>
        /// </summary>
        /// <param name="key"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async Task<byte[]?> HashGetBytesAsync(string key, string field) {
            var r = await (await GetDatabaseAsync()).HashGetAsync(GetKey(key), field);
            return r.IsNullOrEmpty ? default : r;
        }
        #endregion
    }
}
